package com.zenchn.utils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * 日期时间处理类
 *
 * @author dingxinfa
 * @date 2018-08-15
 **/
public class DateUtils {



	/**
	 *  获取当前时间所在星期的年份
	 * @param date
	 * @return
	 */
	public static int getYearOfWeek(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
		c.set(Calendar.HOUR_OF_DAY,0);
		c.set(Calendar.MINUTE,0);
		c.set(Calendar.SECOND,0);
		c.set(Calendar.MILLISECOND,0);


		return c.get(Calendar.YEAR);
	}

	/**
	 * 获取当前时间所在年的周数
	 * @param date
	 * @return
	 */
	public static int getWeekOfYear(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);

		int currYear = c.get(Calendar.YEAR);
		int currWeek = c.get(Calendar.WEEK_OF_YEAR);
		c.add(Calendar.DATE, 7);

		int nextWeek=c.get(Calendar.WEEK_OF_YEAR);
		int nextYear=c.get(Calendar.YEAR);

		if (currYear<nextYear){
			return currWeek;
		}else{
			return currWeek<nextWeek?currWeek:nextWeek-1;
		}
	}

	/**
	 *  获取确定年 的最大周数
	 * @param year
	 * @return
	 */
	public static int getMaxWeekNumOfYear(int year) {
		Calendar c = new GregorianCalendar();
		c.set(year, Calendar.DECEMBER, 31, 23, 59, 59);

		return getWeekOfYear(c.getTime());
	}

	/**
	 *  获取某年的第几周的开始日期
	 * @param year
	 * @param week
	 * @return
	 */
	public static Date getFirstDayOfWeek(int year, int week) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);

		c.set(Calendar.YEAR, year);
		c.set(Calendar.WEEK_OF_YEAR, week);
		c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

		Calendar cal = (GregorianCalendar) c.clone();
		cal.set(Calendar.HOUR_OF_DAY,0);
		cal.set(Calendar.MINUTE,0);
		cal.set(Calendar.SECOND,0);
		cal.set(Calendar.MILLISECOND,0);
		return getFirstDayOfWeek(cal.getTime());
	}

	/**
	 *  获取某年的第几周的结束日期
	 * @param year
	 * @param week
	 * @return
	 */
	public static Date getLastDayOfWeek(int year, int week) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.set(Calendar.YEAR, year);
		c.set(Calendar.WEEK_OF_YEAR, week);
		c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);

		Calendar cal = (GregorianCalendar) c.clone();
		cal.set(Calendar.HOUR_OF_DAY,23);
		cal.set(Calendar.MINUTE,59);
		cal.set(Calendar.SECOND,59);
		cal.set(Calendar.MILLISECOND,999);
		return getLastDayOfWeek(cal.getTime());
	}

	/**
	 *  获取当前时间所在周的开始日期
	 * @param date
	 * @return
	 */
	public static Date getFirstDayOfWeek(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
		c.set(Calendar.HOUR_OF_DAY,0);
		c.set(Calendar.MINUTE,0);
		c.set(Calendar.SECOND,0);
		c.set(Calendar.MILLISECOND,0);
		
		return c.getTime();
	}

	/**
	 *  获取当前时间所在周的结束日期
	 * @param date
	 * @return
	 */
	public static Date getLastDayOfWeek(Date date) {
		Calendar c = new GregorianCalendar();
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		c.setTime(date);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6);
		c.set(Calendar.HOUR_OF_DAY,23);
		c.set(Calendar.MINUTE,59);
		c.set(Calendar.SECOND,59);
		c.set(Calendar.MILLISECOND,999);
		return c.getTime();
	}

	/**
	 *  获取当前时间所在月份的开始日期
	 * @param date
	 * @return
	 */
	public static Date getFirstDayOfMonth(Date date) {
		Calendar c = new GregorianCalendar();
		c.setTime(date);
		c.set(Calendar.DAY_OF_MONTH, 1);
		c.set(Calendar.HOUR_OF_DAY,0);
		c.set(Calendar.MINUTE,0);
		c.set(Calendar.SECOND,0);
		c.set(Calendar.MILLISECOND,0);

		return c.getTime();
	}

	/**
	 *  获取当前时间所在月份的结束日期
	 * @param date
	 * @return
	 */
	public static Date getLastDayOfMonth(Date date) {
		Calendar c = new GregorianCalendar();
		c.setTime(date);
		//获取某月最大天数
		int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		c.set(Calendar.DAY_OF_MONTH, lastDay);
		c.set(Calendar.HOUR_OF_DAY,23);
		c.set(Calendar.MINUTE,59);
		c.set(Calendar.SECOND,59);
		c.set(Calendar.MILLISECOND,999);
		return c.getTime();
	}



	/**
	 *  获取某年第几月的开始日期
	 * @param year
	 * @param month
	 * @return
	 */
	public static Date getFirstDayOfMonth(int year, int month) {
		Calendar cal = new GregorianCalendar();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH,month);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.set(Calendar.HOUR_OF_DAY,0);
		cal.set(Calendar.MINUTE,0);
		cal.set(Calendar.SECOND,0);
		cal.set(Calendar.MILLISECOND,0);
		return cal.getTime();
	}

	/**
	 *  获取某年第几月的结束日期
	 * @param year
	 * @param month
	 * @return
	 */
	public static Date getLastDayOfMonth(int year, int month) {
		Calendar cal = new GregorianCalendar();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH,month);
		//获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        cal.set(Calendar.DAY_OF_MONTH, lastDay);
        cal.set(Calendar.HOUR_OF_DAY,23);
        cal.set(Calendar.MINUTE,59);
        cal.set(Calendar.SECOND,59);
        cal.set(Calendar.MILLISECOND,999);
		return cal.getTime();
	}


	/**
	 *  获取今天开始时间
	 * @return
	 */
	public static Date getTodayStartTime() {
		Calendar cal = new GregorianCalendar();
		cal.setTime(new Date());
		cal.set(Calendar.HOUR_OF_DAY,0);
		cal.set(Calendar.MINUTE,0);
		cal.set(Calendar.SECOND,0);
		cal.set(Calendar.MILLISECOND,0);
		return cal.getTime();
	}

	/**
	 *  获取今天结束时间

	 * @return
	 */
	public static Date getTodayEndTime() {
		Calendar cal = new GregorianCalendar();
		cal.setTime(new Date());
		cal.set(Calendar.HOUR_OF_DAY,23);
		cal.set(Calendar.MINUTE,59);
		cal.set(Calendar.SECOND,59);
		cal.set(Calendar.MILLISECOND,999);
		return cal.getTime();
	}

	/**
	 *  获取某一时间开始时间
	 * @param date 某天的某一时间
	 * @return
	 */
	public static Date getOneDayStartTime(Date date) {
		Calendar cal = new GregorianCalendar();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY,0);
		cal.set(Calendar.MINUTE,0);
		cal.set(Calendar.SECOND,0);
		cal.set(Calendar.MILLISECOND,0);
		return cal.getTime();
	}

	/**
	 * 获取某一时间结束时间
	 * @param date 某天的某一时间
	 * @return
	 */
	public static Date getOneDayEndTime(Date date) {
		Calendar cal = new GregorianCalendar();
		cal.setTime(date);
		cal.set(Calendar.HOUR_OF_DAY,23);
		cal.set(Calendar.MINUTE,59);
		cal.set(Calendar.SECOND,59);
		cal.set(Calendar.MILLISECOND,999);
		return cal.getTime();
	}


	/**
	 * date2比date1多的天数
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static int differentDays(Date date1,Date date2) {
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date1);

		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(date2);
		int day1= cal1.get(Calendar.DAY_OF_YEAR);
		int day2 = cal2.get(Calendar.DAY_OF_YEAR);

		int year1 = cal1.get(Calendar.YEAR);
		int year2 = cal2.get(Calendar.YEAR);
		if(year1 != year2){
			//不同年份
			int timeDistance = 0 ;
			for(int i = year1 ; i < year2 ; i ++){
				if(i%4==0 && i%100!=0){
					//闰年
					timeDistance += 366;
				} else if (i%400==0) {
					//闰年
					timeDistance += 366;
				}else{
					//非闰年
					timeDistance += 365;
				}
			}
			return timeDistance + (day2-day1) ;
		} else {
			//同一年份
			return day2-day1;
		}
	}

	/**
	 *  获取两个日期相差的月数
	 * @param maxTime    较大的日期
	 * @param minTime    较小的日期
	 * @return  如果d1>d2返回 月数差 否则返回0
	 */
	public static int differentMonths( Date minTime,Date maxTime) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(maxTime);
		c2.setTime(minTime);
		if(c1.getTimeInMillis() < c2.getTimeInMillis()) {
			return 0;
		}
		int year1 = c1.get(Calendar.YEAR);
		int year2 = c2.get(Calendar.YEAR);
		int month1 = c1.get(Calendar.MONTH);
		int month2 = c2.get(Calendar.MONTH);

		int monthInterval =0;
		int yearInterval =0;
		if (month1>=month2){
			yearInterval = year1 - year2;
			monthInterval = month1 - month2  ;
		}else{
			yearInterval = year1 - year2-1;
			monthInterval = (month1+12) - month2  ;
		}
		return yearInterval * 12 + monthInterval;
	}


	/**
	 * 将毫秒数 转换成 格式化时间
	 * @param time
	 * @return
	 */
	public static String formatMillisecond(long time){
		return formatSecond(time/1000);
	}

	/**
	 * 将秒数 转换成 格式化时间
	 * @param time
	 * @return
	 */
	public static String formatSecond(long time){
		return formatSecond(time,"天" ,"小时","分钟","秒");
	}

	/**
	 * 将秒数 转换成 格式化时间
	 * @param time
	 * @return
	 */
	public static String formatSecond(long time,String dayFormat,String hourFormat,String minuteFormat,String secondFormat) {
		int mi = 60;
		int hh = mi * 60;
		int dd = hh * 24;

		long day = time / dd;
		long hour = (time%dd) / hh;
		long minute = (time%hh) / mi;
		long second = time%mi;

		StringBuilder formatTime=new StringBuilder();
		if (day>0){
			formatTime.append(day).append(dayFormat);
		}
		if (hour>0 || ((second>0 || minute>0)&& day > 0)){
			formatTime.append(hour).append(hourFormat);
		}
		if (minute>0 ||((hour>0 ||day > 0) && second>0)){
			formatTime.append(minute).append(minuteFormat);
		}
		if (second>0){
			formatTime.append(second).append(secondFormat);
		}
		return formatTime.toString();
	}

	/***
	 * 获取时间区间 月份开始|结束 时间列表
	 * 示例
	 * 	param
	 * 		startLocalDateTime 2020-03-02 12:22:22
	 * 		endLocalDateTime  2020-05-22 18:18:18
	 * 	return
	 * 		2020-03-02 12:22:22,2020-03-31 23:59:59.999
	 * 		2020-04-01 00:00:00,2020-04-30 23:59:59.999
	 * 		2020-05-01 00:00:00,2020-05-22 18:18:18
	 * @param startLocalDateTime
	 * @param endLocalDateTime
	 * @return
	 */
	public static List<LocalDateTime[]> getLocalDateTimeIntervalMonthStartEndTime(LocalDateTime startLocalDateTime,LocalDateTime endLocalDateTime){
		if (startLocalDateTime.isAfter(endLocalDateTime)){
			LocalDateTime temp=startLocalDateTime;
			startLocalDateTime=endLocalDateTime;
			endLocalDateTime=temp;
		}
		List<LocalDateTime[]> localDateTimeList=new ArrayList<>();

		LocalDateTime currDateTime=startLocalDateTime;
		LocalDateTime currMonthEndDateTime = LocalDateTime.of(LocalDate.of(currDateTime.getYear(),currDateTime.getMonth(),currDateTime.getDayOfMonth()), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());

		if (currMonthEndDateTime.isBefore(endLocalDateTime)) {
			localDateTimeList.add(new LocalDateTime[]{currDateTime, currMonthEndDateTime});
		} else {
			localDateTimeList.add(new LocalDateTime[]{startLocalDateTime, endLocalDateTime});
		}

		do{
			currDateTime = LocalDateTime.of(LocalDate.of(currDateTime.getYear(),currDateTime.getMonth(),currDateTime.getDayOfMonth()), LocalTime.MIN).with(TemporalAdjusters.firstDayOfNextMonth());
			currMonthEndDateTime = LocalDateTime.of(LocalDate.of(currDateTime.getYear(),currDateTime.getMonth(),currDateTime.getDayOfMonth()), LocalTime.MAX).with(TemporalAdjusters.lastDayOfMonth());
			if (currMonthEndDateTime.isBefore(endLocalDateTime)) {
				localDateTimeList.add(new LocalDateTime[]{currDateTime, currMonthEndDateTime});
			} else {
				if (currDateTime.isBefore(endLocalDateTime)) {
					localDateTimeList.add(new LocalDateTime[]{currDateTime, endLocalDateTime});
				}
			}
		}while(currMonthEndDateTime.isBefore(endLocalDateTime));

		return localDateTimeList;
	}

	public static void main(String[] args) {
		List<LocalDateTime[]> localDateTimeList=getLocalDateTimeIntervalMonthStartEndTime(LocalDateTime.of(2020,5,30,12,12,12,256),LocalDateTime.of(2020,5,30,12,12,12,888));

		System.out.println(localDateTimeList.toArray().toString());

	}
}